import csv
import os
from typing import Callable

from generateText import TextGenerator


def cache_result(strategy: str) -> Callable:
    def decorator(func: Callable) -> Callable:
        func.__annotations__['cache'] = strategy
        return func

    return decorator


class RowNumberOutOfRangeException(Exception):
    pass


class MyCSV:

    @cache_result('lru')
    def __init__(self, filename: str) -> None:
        self.rows = None
        self.filename = filename

    # 尝试加载csv文件,如果不存在则创建
    @cache_result('fifo')
    def load(self) -> None:
        try:
            self.rows = []
            with open(self.filename, 'r', newline='', encoding="utf-8") as f:
                reader = csv.reader(f)
                for row in reader:
                    self.rows.append(row)
        except FileNotFoundError:
            with open(self.filename, 'w', newline='', encoding="utf-8") as f:
                pass

    # 从内存中插入数据,并调用write_file方法覆盖写入内容到csv

    @cache_result('lru')
    def insert(self, row_number: int, content: str) -> None:
        if row_number < len(self.rows) != 0:
            del self.rows[row_number]
        self.rows.insert(row_number, [content])
        self.write_file()

    # 从内存中删除数据,并调用write_file方法覆盖写入内容到csv
    # 为了确保没有索引溢出,增加自定义异常RowNumberOutOfRangeError判断行号是否超出范围
    @cache_result('lru')
    def delete(self, row_number: int) -> None:
        if row_number >= len(self.rows):
            raise RowNumberOutOfRangeException("Row number out of range")
        del self.rows[row_number]
        self.write_file()

    # 显示行号
    @cache_result('lru')
    def show(self, row_number: int) -> None:
        print(self.rows[row_number])

    # 覆盖写入内容到csv
    @cache_result('lru')
    def write_file(self) -> None:
        with open(self.filename, 'w', newline='', encoding="utf-8") as f:
            writer = csv.writer(f)
            writer.writerows(self.rows)

    # 通过迭代只读取指定行到CSV中,不会全部加载到内存


@cache_result('lru')
def txt2csv(txt_file: str, csv_file: str, start: int, end: int) -> None:
    with open(txt_file) as tf, open(csv_file, 'a') as cf:
        writer = csv.writer(cf)
        for i, line in enumerate(tf):
            if start <= i < end:
                writer.writerow([line])


if __name__ == "__main__":
    txt_filename = 'annotation.txt'
    csv_filename = 'annotation.csv'
    csv_file = MyCSV(csv_filename)

    csv_file.load()

    for i in range(0, 99):
        csv_file.insert(i, "frank")
        csv_file.write_file()
        csv_file.show(i)

    for i in range(0, 99):
        csv_file.insert(i, "charlie")
        csv_file.write_file()
        csv_file.show(i)

    for i in range(0, 99):
        csv_file.delete(0)

    if os.path.exists(csv_file.filename):
        os.remove(csv_file.filename)

    text_gen = TextGenerator()
    text_gen.generate(txt_filename, 100000000, 'xxx')
    txt2csv(txt_filename, csv_filename, 0, 1000)
